<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JS的闭包说明(JS Closure Description)</title>
  <!-- 
  在JavaScript中，闭包（Closure）是一个重要的概念，它允许函数访问其外部作用域的变量，即使在外部函数已经返回的情况下。闭包是JavaScript中函数式编程的一个核心特性，理解闭包对于编写高效和灵活的代码至关重要。以下是对JavaScript闭包的总结说明：

  一、闭包的定义
  闭包是指一个函数（内部函数）可以“记住”并访问其外部函数的变量，即使外部函数已经执行完毕。换句话说，闭包是由函数及其相关的引用环境组合而成的。

  二、闭包的创建
  闭包通常在以下情况下创建：
  1. 函数嵌套：当一个函数被定义在另一个函数内部时，内部函数就形成了闭包。
    function outerFunction() {
        let outerVariable = 'I am outside!';

        function innerFunction() {
            console.log(outerVariable); // 访问外部变量
        }

        return innerFunction; // 返回内部函数
    }

    const closureFunction = outerFunction();
    closureFunction(); // 输出: I am outside!
  三、闭包的特点
  1. 持久化状态：闭包可以持久化外部函数的状态，允许内部函数在外部函数执行完后仍然访问这些变量。

  2. 私有变量：通过闭包，可以创建私有变量，外部代码无法直接访问这些变量，从而实现数据封装。
    function createCounter() {
        let count = 0; // 私有变量

        return {
            increment: function() {
                count += 1;
                return count;
            },
            decrement: function() {
                count -= 1;
                return count;
            },
            getCount: function() {
                return count;
            }
        };
    }

    const counter = createCounter();
    console.log(counter.increment()); // 输出: 1
    console.log(counter.increment()); // 输出: 2
    console.log(counter.getCount());  // 输出: 2
  四、闭包的应用场景
  1. 数据封装：使用闭包可以隐藏实现细节，只暴露必要的接口。
  2. 工厂函数：闭包可以用于创建具有独立状态的多个实例。
  3. 回调函数：闭包允许回调函数访问其创建时的上下文。
  4. 事件处理：在事件处理程序中，闭包可以保持对某些变量的引用。

  五、闭包的注意事项
  1. 内存泄漏：由于闭包会保持对外部变量的引用，如果不加以管理，可能导致内存泄漏。
  2. 性能问题：过多的闭包可能会影响性能，尤其是在频繁创建和销毁闭包的情况下。

  六、总结
  - 闭包是一个函数及其相关的引用环境的组合，允许函数访问其外部作用域的变量。
  - 持久化状态和私有变量是闭包的两个主要特点。
  - 应用广泛，包括数据封装、工厂函数、回调函数和事件处理等。
  - 需要注意内存管理和性能问题。
   -->
</head>

<body>

  <script>
    // 1. 持久化状态 和 私有变量
    function createCounter() {
      let count = 0; // 私有变量

      return {
        increment: function () {
          count += 1;
          return count;
        },
        decrement: function () {
          count -= 1;
          return count;
        },
        getCount: function () {
          return count;
        }
      };
    }

    const counter = createCounter();
    console.log(counter.increment()); // 输出: 1
    console.log(counter.increment()); // 输出: 2
    console.log(counter.getCount());  // 输出: 2

    // 2. 工厂函数
    function createPerson(name, age) {
      return {
        getName: function () {
          return name;
        },
        getAge: function () {
          return age;
        }
      };
    }

    const person1 = createPerson('Alice', 25);
    console.log(person1.getName()); // 输出: Alice
  </script>

</body>

</html>